package com.kds.smarthome.service;

import com.kds.smarthome.common.DateType;
import com.kds.smarthome.common.EnergyValue;
import com.kds.smarthome.controller.vo.DateObject;
import com.kds.smarthome.controller.vo.MeterData;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 孔德嵩
 * 创建日期 2025/3/31
 */
@Service
public class MongoAggregationQuery {
    @Autowired
    private MongoClient mongoClient; // 注入 Spring 自动配置的 MongoClient

    // 获取 smarthome 数据库
    public MongoDatabase getSmartHomeDatabase() {
        return mongoClient.getDatabase("smarthome");
    }

    public List<MeterData> metersMultiDaysQuery(List<String> fids, DateType type, List<DateObject> dateObjects) {
        MongoCollection<Document> collection = getSmartHomeDatabase().getCollection("data");

        // 构建时间条件
        List<Document> timeConditions = dateObjects.stream()
                .map(dateObj -> new Document("ts",
                        new Document("$gte", dateObj.getStartTime())
                                .append("$lt", dateObj.getEndTime())))
                .collect(Collectors.toList());

        // 构建聚合管道
        AggregateIterable<Document> result = collection.aggregate(Arrays.asList(
                // Match 阶段：根据时间范围和 fid 过滤
                new Document("$match",
                        new Document("$and", Arrays.asList(
                                new Document("$or", timeConditions),
                                new Document("fid", new Document("$in", fids))
                        ))
                ),

                // 添加本地日期和小时字段
                new Document("$addFields",
                        new Document("localDate",
                                new Document("$dateToString",
                                        new Document("format", "%Y-%m-%d")
                                                .append("date", "$ts")
                                                .append("timezone", "+08:00")))
                                .append("hour",
                                        new Document("$hour",
                                                new Document("date", "$ts")
                                                        .append("timezone", "+08:00")))),

                // ... 其他聚合阶段保持不变 ...
                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$fid")
                                        .append("dateValue", "$localDate")
                                        .append("hour", "$hour"))
                                .append("firstRecord",
                                        new Document("$first", "$$ROOT"))
                                .append("lastRecord",
                                        new Document("$last", "$$ROOT"))),

                new Document("$addFields",
                        new Document("deltaValue",
                                new Document("$subtract", Arrays.asList("$lastRecord.value", "$firstRecord.value")))
                                .append("deltaMillis",
                                        new Document("$subtract", Arrays.asList("$lastRecord.ts", "$firstRecord.ts")))),

                new Document("$addFields",
                        new Document("hourlyRate",
                                new Document("$cond", Arrays.asList(
                                        new Document("$eq", Arrays.asList("$deltaMillis", 0L)),
                                        0L,
                                        new Document("$divide", Arrays.asList(
                                                new Document("$multiply", Arrays.asList("$deltaValue", 60L)),
                                                new Document("$divide", Arrays.asList("$deltaMillis", 60000L))
                                        ))
                                )))),

                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$_id.fid")
                                        .append("dateValue", "$_id.dateValue"))
                                .append("data",
                                        new Document("$push",
                                                new Document("index", "$_id.hour")
                                                        .append("value",
                                                                new Document("$round", Arrays.asList("$hourlyRate", 2L)))))),

                new Document("$addFields",
                        new Document("data",
                                new Document("$sortArray",
                                        new Document("input", "$data")
                                                .append("sortBy",
                                                        new Document("index", 1L))))),

                new Document("$project",
                        new Document("_id", 0L)
                                .append("fid", "$_id.fid")
                                .append("dateValue", "$_id.dateValue")
                                .append("dateType", "day")
                                .append("data", 1L))
        ));

        // 转换结果为 List<MeterData>
        List<MeterData> meterDataList = new ArrayList<>();
        result.forEach(doc -> {
            MeterData meterData = new MeterData();
            meterData.setFid(doc.getString("fid"));
            meterData.setDateValue(doc.getString("dateValue"));
            meterData.setDateType(doc.getString("dateType"));

            List<Document> dataPoints = (List<Document>) doc.get("data");
            List<EnergyValue> energyValues = dataPoints.stream()
                    .map(point -> {
                        EnergyValue value = new EnergyValue();
                        value.setIndex(point.getInteger("index"));

                        // 安全处理 value 字段（浮点型）
                        Object valueObj = point.get("value");
                        if (valueObj instanceof Number) {
                            value.setValue(((Number) valueObj).doubleValue());
                        } else {
                            value.setValue(0.0); // 默认值或抛异常
                        }

                       // value.setValue(point.getDouble("value"));
                        return value;
                    })
                    .collect(Collectors.toList());

            meterData.setData(energyValues);
            meterDataList.add(meterData);
        });

        return meterDataList;
    }

    public List<MeterData> metersMultiMonthsQuery(List<String> fids, DateType type, List<DateObject> dateObjects) {

        MongoCollection<Document> collection = getSmartHomeDatabase().getCollection("data");

        // 构建时间条件
        List<Document> timeConditions = dateObjects.stream()
                .map(dateObj -> new Document("ts",
                        new Document("$gte", dateObj.getStartTime())
                                .append("$lt", dateObj.getEndTime())))
                .collect(Collectors.toList());

        // 构建聚合管道
        AggregateIterable<Document> result = collection.aggregate(Arrays.asList(
                // Match 阶段：根据时间范围和 fid 过滤
                new Document("$match",
                        new Document("$and", Arrays.asList(
                                new Document("$or", timeConditions),
                                new Document("fid", new Document("$in", fids))
                        ))
                ),

                // 添加本地日期和小时字段
                new Document("$addFields",
                        new Document("localDate",
                                new Document("$dateToString",
                                        new Document("format", "%Y-%m")
                                                .append("date", "$ts")
                                                .append("timezone", "+08:00")))
                                .append("day",
                                        new Document("$dayOfMonth",
                                                new Document("date", "$ts")
                                                        .append("timezone", "+08:00")))),

                // ... 其他聚合阶段保持不变 ...
                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$fid")
                                        .append("dateValue", "$localDate")
                                        .append("day", "$day"))
                                .append("firstRecord",
                                        new Document("$first", "$$ROOT"))
                                .append("lastRecord",
                                        new Document("$last", "$$ROOT"))),

                new Document("$addFields",
                        new Document("deltaValue",
                                new Document("$subtract", Arrays.asList("$lastRecord.value", "$firstRecord.value")))
//                                .append("deltaMillis",
//                                        new Document("$subtract", Arrays.asList("$lastRecord.ts", "$firstRecord.ts")))
                ),

                // 日数据不再做归一化填充
//                new Document("$addFields",
//                        new Document("dailyRate",
//                                new Document("$cond", Arrays.asList(
//                                        new Document("$eq", Arrays.asList("$deltaMillis", 0L)),
//                                        0L,
//                                        new Document("$divide", Arrays.asList(
//                                                new Document("$multiply", Arrays.asList("$deltaValue", 24L)),
//                                                new Document("$divide", Arrays.asList("$deltaMillis", 3600000L))
//                                        ))
//                                )))),

                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$_id.fid")
                                        .append("dateValue", "$_id.dateValue"))
                                .append("data",
                                        new Document("$push",
                                                new Document("index", "$_id.day")
                                                        .append("value",
                                                                new Document("$round", Arrays.asList("$deltaValue", 1L)))))),

                new Document("$addFields",
                        new Document("data",
                                new Document("$sortArray",
                                        new Document("input", "$data")
                                                .append("sortBy",
                                                        new Document("index", 1L))))),

                new Document("$project",
                        new Document("_id", 0L)
                                .append("fid", "$_id.fid")
                                .append("dateValue", "$_id.dateValue")
                                .append("dateType", "month")
                                .append("data", 1L))
        ));

        // 转换结果为 List<MeterData>
        List<MeterData> meterDataList = new ArrayList<>();
        result.forEach(doc -> {
            MeterData meterData = new MeterData();
            meterData.setFid(doc.getString("fid"));
            meterData.setDateValue(doc.getString("dateValue"));
            meterData.setDateType(doc.getString("dateType"));

            List<Document> dataPoints = (List<Document>) doc.get("data");
            List<EnergyValue> energyValues = dataPoints.stream()
                    .map(point -> {
                        EnergyValue value = new EnergyValue();
                        value.setIndex(point.getInteger("index"));

                        // 修复类型转换问题：将值统一转为 Double
                        Object rawValue = point.get("value");
                        if (rawValue instanceof Number) {
                            value.setValue(((Number) rawValue).doubleValue());
                        } else {
                            // 处理非数值类型或空值（根据业务逻辑调整）
                            value.setValue(0.0); // 默认值或抛出异常
                        }

                        return value;
                    })
                    .collect(Collectors.toList());

            meterData.setData(energyValues);
            meterDataList.add(meterData);
        });

        return meterDataList;
    }


    public List<MeterData> metersMultiYearsQuery(List<String> fids, DateType type, List<DateObject> dateObjects) {

        MongoCollection<Document> collection = getSmartHomeDatabase().getCollection("data");

        // 构建时间条件
        List<Document> timeConditions = dateObjects.stream()
                .map(dateObj -> new Document("ts",
                        new Document("$gte", dateObj.getStartTime())
                                .append("$lt", dateObj.getEndTime())))
                .collect(Collectors.toList());

        // 构建聚合管道
        AggregateIterable<Document> result = collection.aggregate(Arrays.asList(
                // Match 阶段：根据时间范围和 fid 过滤
                new Document("$match",
                        new Document("$and", Arrays.asList(
                                new Document("$or", timeConditions),
                                new Document("fid", new Document("$in", fids))
                        ))
                ),

                // 添加本地日期和小时字段
                new Document("$addFields",
                        new Document("localDate",
                                new Document("$dateToString",
                                        new Document("format", "%Y")
                                                .append("date", "$ts")
                                                .append("timezone", "+08:00")))
                                .append("month",
                                        new Document("$month",
                                                new Document("date", "$ts")
                                                        .append("timezone", "+08:00")))),

                // ... 其他聚合阶段保持不变 ...
                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$fid")
                                        .append("dateValue", "$localDate")
                                        .append("month", "$month"))
                                .append("firstRecord",
                                        new Document("$first", "$$ROOT"))
                                .append("lastRecord",
                                        new Document("$last", "$$ROOT"))),

                new Document("$addFields",
                        new Document("deltaValue",
                                new Document("$subtract", Arrays.asList("$lastRecord.value", "$firstRecord.value")))),
//                                .append("deltaMillis",
//                                        new Document("$subtract", Arrays.asList("$lastRecord.ts", "$firstRecord.ts")))),
                //不对每个月进行数据进行修正

                new Document("$group",
                        new Document("_id",
                                new Document("fid", "$_id.fid")
                                        .append("dateValue", "$_id.dateValue"))
                                .append("data",
                                        new Document("$push",
                                                new Document("index", "$_id.month")
                                                        .append("value",
                                                                new Document("$round", Arrays.asList("$deltaValue", 1L)))))),

                new Document("$addFields",
                        new Document("data",
                                new Document("$sortArray",
                                        new Document("input", "$data")
                                                .append("sortBy",
                                                        new Document("index", 1L))))),

                new Document("$project",
                        new Document("_id", 0L)
                                .append("fid", "$_id.fid")
                                .append("dateValue", "$_id.dateValue")
                                .append("dateType", "year")
                                .append("data", 1L))
        ));

        // 转换结果为 List<MeterData>
        List<MeterData> meterDataList = new ArrayList<>();
        result.forEach(doc -> {
            MeterData meterData = new MeterData();
            meterData.setFid(doc.getString("fid"));
            meterData.setDateValue(doc.getString("dateValue"));
            meterData.setDateType(doc.getString("dateType"));

            List<Document> dataPoints = (List<Document>) doc.get("data");
            List<EnergyValue> energyValues = dataPoints.stream()
                    .map(point -> {
                        EnergyValue value = new EnergyValue();
                        value.setIndex(point.getInteger("index"));
                        value.setValue(point.getDouble("value"));
                        return value;
                    })
                    .collect(Collectors.toList());

            meterData.setData(energyValues);
            meterDataList.add(meterData);
        });

        return meterDataList;

    }


    public List<MeterData> metersMultiDatesQuery(List<String> fids, DateType type, List<DateObject> dateObjects) {


        switch (type) {

            case DAY:
                return metersMultiDaysQuery(fids, type, dateObjects);
            case MONTH:
                return metersMultiMonthsQuery(fids, type, dateObjects);
            case YEAR:
                return metersMultiYearsQuery(fids, type, dateObjects);
        }

        throw new IllegalArgumentException("无对应DateType=" + type);
    }
}
